﻿using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using C1.Silverlight;
using System.ComponentModel;

namespace ControlExplorer
{
    public class ContentLoader : DependencyObject, INavigationContentLoader, INotifyPropertyChanged
    {
        private INavigationContentLoader resourceLoader = new PageResourceContentLoader();
        private Uri _targetUri;
        private Uri _currentUri;

        public Frame Frame
        {
            get { return (Frame)GetValue(FrameProperty); }
            set { SetValue(FrameProperty, value); }
        }

        public static readonly DependencyProperty FrameProperty =
            DependencyProperty.Register("Frame", typeof(Frame), typeof(ContentLoader), new PropertyMetadata(null));


        double _percentage = double.NaN;
        Visibility _percentageVisibility = Visibility.Visible;

        public string Percentage
        {
            get
            {
                return double.IsNaN(_percentage) ? "Loading..." : string.Format("{0:P0}", _percentage);
            }
        }

        public Visibility PercentageVisibility
        {
            get
            {
                return _percentageVisibility;
            }
            set
            {
                _percentageVisibility = value;
                RaisePropertyChanged("PercentageVisibility");
            }
        }

        public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState)
        {
            _currentUri = currentUri;
            _targetUri = targetUri;
            IAsyncResult result = new AsyncResult(asyncState);
            Action load = () =>
                {

                    _percentage = double.NaN;
                    RaisePropertyChanged("Percentage");
                    if (!targetUri.OriginalString.StartsWith("/Views"))
                    {
                        var feature = MainViewModel.Instance.Features.FirstOrDefault(f => f.Link.OriginalString == targetUri.OriginalString);

                        // request to load the external module..
                        var info = new C1AssemblyLoaderInfo()
                        {
                            AssemblyName = feature.AssemblyName,
                            PackageUri = feature.PackageUri,
                        };

                        PercentageVisibility = Visibility.Visible;
                        C1AssemblyLoaderManager.Load(info,
                            // progress changed
                            (s, e) =>
                            {
                                _percentage = (double)e.ProgressPercentage / 100.0;
                                RaisePropertyChanged("Percentage");
                            },
                            // loaded 
                            (s, e) =>
                            {
                                feature.Sample = e.Assembly.CreateInstance(feature.FullDemoControlTypeName) as FrameworkElement;
                                targetUri = new Uri(PlatformUtils.AdjustPlatformXamlName("/Views/SamplePage.xaml", false), UriKind.Relative);
                                var r = resourceLoader.BeginLoad(targetUri, currentUri, userCallback, asyncState);
                                PercentageVisibility = Visibility.Collapsed;
                            },
                            // error
                            (s, e) =>
                            {
                                PercentageVisibility = Visibility.Collapsed;
#if (DEBUG)
                                System.Diagnostics.Debug.WriteLine("** " + e.Exception.ToString());
                                WebException ex = e.Exception as WebException;
                                if (ex != null)
                                {
                                    if (ex.Response != null && ex.Response.ResponseUri != null)
                                    {
                                        System.Diagnostics.Debug.WriteLine("** " + ex.Response.ResponseUri.OriginalString);
                                    }
                                    else
                                    {
                                        System.Diagnostics.Debug.WriteLine("** ! make sure that ControlExplorer2010Web project is set as StartUp project !");
                                    }
                                }
#endif
                                Frame.ShowNavigationError(targetUri);
                            });
                    }
                    else
                    {
                        var r = resourceLoader.BeginLoad(targetUri, currentUri, userCallback, asyncState);
                        PercentageVisibility = Visibility.Collapsed;
                    }
                };

            if (currentUri != null && !string.IsNullOrWhiteSpace(currentUri.OriginalString))
            {
                Frame.ContentUnloaded(_currentUri, _targetUri, () =>
                    {
                        load();
                    });
            }
            else
            {
                load();
            }

            return result;
        }

        public bool CanLoad(Uri targetUri, Uri currentUri)
        {
            if (targetUri.OriginalString.StartsWith("/Views"))
            {
                return resourceLoader.CanLoad(targetUri, currentUri);
            }
            else
            {
                var feature = MainViewModel.Instance.Features.FirstOrDefault(f => f.Link.OriginalString == targetUri.OriginalString);
                return feature != null;
            }
        }

        public void CancelLoad(IAsyncResult asyncResult)
        {
            resourceLoader.CancelLoad(asyncResult);
        }

        public LoadResult EndLoad(IAsyncResult asyncResult)
        {
            var result = resourceLoader.EndLoad(asyncResult);
            Dispatcher.BeginInvoke(() =>
                {
                    (result.LoadedContent as FrameworkElement).UpdateLayout();
                    Frame.ContentLoaded(_currentUri, _targetUri);
                });
            return result;
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class AsyncResult : IAsyncResult
    {
        private object _asyncState;

        public AsyncResult(object asyncState)
        {
            _asyncState = asyncState;
        }
        public object AsyncState
        {
            get { return _asyncState; }
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get { throw new NotImplementedException(); }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return false; }
        }
    }
}
